import Vue from 'vue'
import { mergeRecursive } from "@/utils/objectUtils";
import DictMeta from './DictMeta'
import DictData from './DictData'

// 默认字典选项
const DEFAULT_DICT_OPTIONS = {
  types: [],
}

/**
 * @classdesc 字典类
 * @property {Object} label 标签对象，内部属性名为字典类型名称
 * @property {Object} type 字段数组，内部属性名为字典类型名称
 * @property {Array.<DictMeta>} _dictMetas 字典元数据数组
 */
export default class Dict {
  constructor() {
    this.owner = null // 拥有者
    this.label = {} // 标签对象
    this.type = {} // 字段数组
  }

  /**
   * 初始化字典
   * @param {Array|Object} options - 字典选项，可以是数组或对象
   * @returns {Promise} - 返回初始化字典的 Promise 对象
   */
  init(options) {
    // 如果选项是数组，则转换为对象形式
    if (options instanceof Array) {
      options = { types: options }
    }
    // 合并默认选项和传入选项
    const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)
    // 检查是否提供了字典类型
    if (opts.types === undefined) {
      throw new Error('need dict types')
    }
    const promises = []
    // 解析字典元数据并初始化字典
    this._dictMetas = opts.types.map(t => DictMeta.parse(t))
    this._dictMetas.forEach(dictMeta => {
      const type = dictMeta.type
      // 使用 Vue.set 方法设置响应式属性
      Vue.set(this.label, type, {})
      Vue.set(this.type, type, [])
      // 如果是延迟加载的字典元数据，则直接返回
      if (dictMeta.lazy) {
        return
      }
      // 加载字典数据，并将加载的 Promise 添加到 promises 数组中
      promises.push(loadDict(this, dictMeta))
    })
    // 返回所有加载字典的 Promise 对象
    return Promise.all(promises)
  }

  /**
   * 重新加载指定类型的字典
   * @param {String} type - 字典类型
   * @returns {Promise} - 返回重新加载字典的 Promise 对象
   */
  reloadDict(type) {
    // 查找指定类型的字典元数据
    const dictMeta = this._dictMetas.find(e => e.type === type)
    if (dictMeta === undefined) {
      return Promise.reject(`the dict meta of ${type} was not found`)
    }
    // 加载字典数据并返回 Promise 对象
    return loadDict(this, dictMeta)
  }
}

/**
 * 加载字典数据
 * @param {Dict} dict - 字典对象
 * @param {DictMeta} dictMeta - 字典元数据
 * @returns {Promise} - 返回加载字典数据的 Promise 对象
 */
function loadDict(dict, dictMeta) {
  // 发起请求获取字典数据
  return dictMeta.request(dictMeta)
    .then(response => {
      const type = dictMeta.type
      // 将响应数据转换为字典数据对象数组
      let dicts = dictMeta.responseConverter(response, dictMeta)
      // 检查转换后的数据类型是否正确
      if (!(dicts instanceof Array)) {
        console.error('the return of responseConverter must be Array.<DictData>')
        dicts = []
      } else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) {
        console.error('the type of elements in dicts must be DictData')
        dicts = []
      }
      // 替换字典数据数组
      dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
      // 更新标签对象
      dicts.forEach(d => {
        Vue.set(dict.label[type], d.value, d.label)
      })
      // 返回加载的字典数据对象数组
      return dicts
    })
}
